#include "Max.h"
#include "XMLUtility.h"
#include "d3d_mesh.h"

CD3DMesh::CD3DMesh()
{

}

CD3DMesh::~CD3DMesh()
{

}

void CD3DMesh::Clear()
{
	_vertex_list.clear();
	_normal_list.clear();
	_uv_list.clear();

	_face_vert_list.clear();
	_face_normal_list.clear();
	_face_uv_list.clear();

	_vertex_skin_list.clear();
}

void CD3DMesh::__ExpandAllVertex(SubMeshD3D& subMesh, vector<D3DVert>& vec)
{
	int iFaceCount = 0;
	for (int i = 0; i < (int)_face_vert_list.size(); ++i)
	{
		if (_face_mtl_id[i] != subMesh.mtlID)
			continue;

		IPoint3& faceIdx = _face_vert_list[i];
		IPoint3& normalIdx = _face_normal_list[i];
		IPoint3& uvIdx = _face_uv_list[i];

		D3DVert d3dv1;
		d3dv1.pos = _vertex_list[faceIdx.x];
		d3dv1.normal = _normal_list[normalIdx.x];
		d3dv1.uv = _uv_list[uvIdx.x];
		d3dv1.original = faceIdx.x;

		D3DVert d3dv2;
		d3dv2.pos = _vertex_list[faceIdx.y];
		d3dv2.normal = _normal_list[normalIdx.y];
		d3dv2.uv = _uv_list[uvIdx.y];
		d3dv2.original = faceIdx.y;

		D3DVert d3dv3;
		d3dv3.pos = _vertex_list[faceIdx.z];
		d3dv3.normal = _normal_list[normalIdx.z];
		d3dv3.uv = _uv_list[uvIdx.z];
		d3dv3.original = faceIdx.z;

		vec.push_back(d3dv1);
		vec.push_back(d3dv2);
		vec.push_back(d3dv3);

		subMesh.face_list.push_back(IPoint3(iFaceCount * 3, iFaceCount * 3 + 1, iFaceCount * 3 + 2));
		++iFaceCount;
	}
}

int CD3DMesh::__FindMaxMtlID()
{
	int id = 0;
	for (int i = 0; i < (int)_face_mtl_id.size(); ++i)
	{
		if (_face_mtl_id[i] > id)
			id = _face_mtl_id[i];
	}

	return id;
}

void CD3DMesh::__CombineSameVertex(vector<D3DVert>& vecExpanded, vector<int>& vecVertexIdx)
{
	for (int i = 0; i < vecExpanded.size(); ++i)
		vecVertexIdx.push_back(-1);

	for (int i = 0; i < vecExpanded.size(); ++i)
	{
		if (vecVertexIdx[i] == -1)
		{
			for (int j = i + 1; j < vecExpanded.size(); ++j)
			{
				if (vecVertexIdx[j] == -1 && vecExpanded[i] == vecExpanded[j])
					vecVertexIdx[j] = i;
			}
		}
	}
}

void CD3DMesh::__AdjustFaceIndex(SubMeshD3D& subMesh, vector<int>& vecVertexIdx)
{
	for (int i = 0; i < subMesh.face_list.size(); ++i)
	{
		IPoint3& face = subMesh.face_list[i];
		if (vecVertexIdx[face.x] != -1)
			face.x = vecVertexIdx[face.x];
		if (vecVertexIdx[face.y] != -1)
			face.y = vecVertexIdx[face.y];
		if (vecVertexIdx[face.z] != -1)
			face.z = vecVertexIdx[face.z];
	}

	for (int i = 0; i < subMesh.face_list.size(); ++i)
	{
		IPoint3& face = subMesh.face_list[i];

		int cnt = face.x;
		for (int j = 0; j < cnt; ++j)
			if (vecVertexIdx[j] != -1)
				face.x -= 1;

		cnt = face.y;
		for (int j = 0; j < cnt; ++j)
			if (vecVertexIdx[j] != -1)
				face.y -= 1;

		cnt = face.z;
		for (int j = 0; j < cnt; ++j)
			if (vecVertexIdx[j] != -1)
				face.z -= 1;
	}
}

void CD3DMesh::__StoreResult(SubMeshD3D& subMesh, vector<D3DVert>& vecExpanded, vector<int>& vecVertexIdx)
{
	for (int i = 0; i < vecExpanded.size(); ++i)
		if (vecVertexIdx[i] == -1)
			subMesh.vert_list.push_back(vecExpanded[i]);
}

bool CD3DMesh::Convert()
{
	if (_face_vert_list.size() != _face_normal_list.size())
		return false;
	if (_face_vert_list.size() != _face_uv_list.size())
		return false;

	int maxMtlID = __FindMaxMtlID();
	for (int i = 0; i <= maxMtlID; ++i)
	{
		_vecSubMeshD3D.push_back(SubMeshD3D());
		SubMeshD3D& subMesh = _vecSubMeshD3D.back();
		subMesh.mtlID = i;

		// expand all vertex.
		vector<D3DVert> vecExpanded;
		__ExpandAllVertex(subMesh, vecExpanded);

		// combine same vertex.
		vector<int> vecVertexIdx;
		__CombineSameVertex(vecExpanded, vecVertexIdx);

		// adjust face index.
		__AdjustFaceIndex(subMesh, vecVertexIdx);

		// store result.
		__StoreResult(subMesh, vecExpanded, vecVertexIdx);
	}

	return true;
}

void CD3DMesh::__WriteSubMesh(SubMeshD3D& subMesh, IXMLDOMDocument* pXMLDoc, CComPtr<IXMLDOMNode> parent)
{
	CComPtr<IXMLDOMNode> d3dVertNode;
	CreateXMLNode(pXMLDoc, parent, _T("D3DVertex"), &d3dVertNode);

	TSTR buf;
	buf.printf("%d", subMesh.vert_list.size());
	AddXMLAttribute(d3dVertNode, _T("Count"), buf.data());

	for (int i = 0; i < subMesh.vert_list.size(); ++i)
	{
		D3DVert& v = subMesh.vert_list[i];

		CComPtr<IXMLDOMNode> vertNode;
		CreateXMLNode(pXMLDoc, d3dVertNode,_T("Vertex"), &vertNode);

		buf.printf("%f %f %f", v.pos.x, v.pos.y, v.pos.z);
		AddXMLAttribute(vertNode, _T("Pos"), buf.data());

		buf.printf("%f %f %f", v.normal.x, v.normal.y, v.normal.z);
		AddXMLAttribute(vertNode, _T("Normal"), buf.data());

		buf.printf("%f %f", v.uv.x, v.uv.y);
		AddXMLAttribute(vertNode, _T("UV"), buf.data());

		buf.printf("%d", v.original);
		AddXMLAttribute(vertNode, _T("Original"), buf.data());
	}

	CComPtr<IXMLDOMNode> d3dFaceNode;
	CreateXMLNode(pXMLDoc, parent,_T("D3DFace"),&d3dFaceNode);

	buf.printf("%d", subMesh.face_list.size());
	AddXMLAttribute(d3dFaceNode, _T("Count"), buf.data());

	for (int i = 0; i < subMesh.face_list.size(); ++i)
	{
		IPoint3& face = subMesh.face_list[i];

		CComPtr<IXMLDOMNode> faceNode;
		CreateXMLNode(pXMLDoc, d3dFaceNode,_T("Face"), &faceNode);

		buf.printf("%d %d %d", face.x, face.y, face.z);
		AddXMLAttribute(faceNode, _T("face"), buf.data());
	}
}

void CD3DMesh::Write(IXMLDOMDocument * pXMLDoc, CComPtr<IXMLDOMNode> parent)
{
	CComPtr<IXMLDOMNode> d3dSubMeshListNode;
	CreateXMLNode(pXMLDoc, parent,_T("D3DSubMeshList"), &d3dSubMeshListNode);

	TSTR buf;
	buf.printf("%d", _vecSubMeshD3D.size());
	AddXMLAttribute(d3dSubMeshListNode, _T("Count"), buf.data());

	for (int i = 0; i < (int)_vecSubMeshD3D.size(); ++i)
	{
		SubMeshD3D& subMesh = *(_vecSubMeshD3D.begin() + i);

		CComPtr<IXMLDOMNode> subMeshNode;
		CreateXMLNode(pXMLDoc, d3dSubMeshListNode,_T("SubMesh"),&subMeshNode);

		TSTR buf;
		buf.printf("%d", subMesh.mtlID);
		AddXMLAttribute(subMeshNode, _T("SubMaterialID"), buf.data());

		__WriteSubMesh(subMesh, pXMLDoc, subMeshNode);
	}
}

